/**
 * Planet.java
 */
// $codepro.audit.disable numericLiterals
package edu.gatech.startrader.universe;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.JOptionPane;

import edu.gatech.startrader.gui.TradeScreen;
import edu.gatech.startrader.player.Player;
import edu.gatech.startrader.trade.Inventory;
import edu.gatech.startrader.trade.TradeGood;

/**
 * Planet Class
 * Holds information on the Planets the Player can travel to and trade with
 * @author Team Bamf (Team 30)
 * @version 1.0
 */
public class Planet {
	/**
	 * Prices HashMap
	 */
	private final Map<TradeGood, Integer> prices;
	
	/**
	 * the Inventory that the trade entity can access
	 */
	private Inventory inventory;
	
	/**
	 * The Special Conditions the Planet may have
	 */
	private final SpecialResources specialResources;
	
	/**
	 * the name of the Planet
	 */
	private final String name;
	
	/**
	 * The Technological Level of the Planet
	 */
	private final TechLevel techLevel;
	
	/**
	 * Whether or not the planet 
	 */
	private final boolean wormhole;
	
	/**
	 * Planet's absolute X Coordinate on the Universe map
	 */
	private final double x;
	
	/**
	 * Planet's absolute Y coordinate on the Universe map
	 */
	private final double y;
	
	/**
	 * Planet Constructor
	 * This sets up a planet with it's position, name, Tech Level and special resources
	 * @param posX the X-position of the planet
	 * @param posY the Y-position of the planet
	 * @param planetName the name of the planet
	 * @param tl the Tech Level of the Planet
	 * @param sr the special resources of the planet
	 * @param w whether the planet has a worm hole or not
	 */
	public Planet(double posX,  // $codepro.audit.disable largeNumberOfParameters
			double posY, 
			String planetName, 
			TechLevel level,
			SpecialResources resource,
			boolean w) {
		x = posX;
		y = posY;
		name = planetName;
		techLevel = level;
		specialResources = resource;
		wormhole = w;
		inventory = new Inventory();
		prices = new HashMap<TradeGood, Integer>(); //sets the prices
		for(int i = 0; i < TradeGood.values().length; i++) {
			prices.put(TradeGood.values()[i], 0);
		}
	}
	
	/**
	 * getTechLevel
	 * Gets the TechLevel of the Planet
	 * @return the Planet's Tech Level
	 */
	public TechLevel getTechLevel() {
		return techLevel;
	}
	
	/**
	 * getSpecialResources method
	 * This method returns the special resources of a planet
	 * @return the special resources 
	 */
	public SpecialResources getSpecialResources() {
		return specialResources;
	}
	
	/**
	 * trade method
	 * Initiates a trade with the Player
	 * @param p the Player
	 */
	public void trade(Player p) {
		TradeScreen.showTradeScreen(null, p, this);
	}
	
	/**
	 * generateResources method
	 * Generates the number resources for the planet to sell to player
	 */
	public void generateResources() {
		getInventory().generateAmount(this);
	}
	
	/**
	 * calculatePrices Method
	 * This method calculates the prices of resources on the selected planet.
	 */
	public void calculatePrices(boolean event) {
		TradeGood[] goods = TradeGood.values();
		for(int i = 0; i < goods.length; i++) {
			prices.put(goods[i], goods[i].calculatePrice(this));
		}
		if(event) {
			final Random rand = new Random();
			if(rand.nextDouble() < 0.25) {
				boolean increase = rand.nextBoolean();
				int price = 0;
				TradeGood good = null;
				String message = null;
				while(price == 0) {
					good = goods[rand.nextInt(goods.length)];
					if(increase) {
						price = (int) (prices.get(good) * (2 + rand.nextDouble() * 3.0));
						message = good.getIncreaseMessage();
					} else {
						price = (int) (prices.get(good) / (2 + rand.nextDouble() * 3.0));
						message = good.getDecreaseMessage();
					}
				}
				prices.put(good, price);
				JOptionPane.showMessageDialog(null, message);
			}
		}
	}
	
	/**
	 * getX method
	 * Gets the X-position of the planet
	 * @return x-position
	 */
	public double getX() {
		return x;
	}
	
	/**
	 * getXY method
	 * Gets the Y-position of the planet
	 * @return y-position
	 */
	public double getY() {
		return y;
	}
	
	/**
	 * hasWorkHole method
	 * Checks whether the Planet has a WormHole
	 * @return whether the Planet has a WormHole
	 */
	public boolean hasWormHole() {
		return wormhole;
	}
	
	/**
	 * toString method
	 * this method takes the planet name, tech level, coordinates, 
	 * and whether it has a wormhole and returns it as a string
	 * @return String containing all the Planet information
	 */
	@Override
	public String toString() {
		return "Planet: " + "\n" +
				"Name: " + name + "\n" + 
				"Tech Level: " + techLevel.toString() + "\n" + 
				"Special Resoures: " + specialResources.toString() + "\n" +
				"Universe Coordinates: X: " + x + " Y: " + y + "\n" +
				((wormhole) ? "Has A Wormhole" : "Has not a Wormhole");
	}
	
	/**
	 * TechLevel Enumerated Type
	 * This lists the types of Tech Levels a planet can have
	 * @author Team Bamf 
	 *
	 */
	public enum TechLevel { 
		PRE_AGRICULTURE(0), 
		AGRICULTURE(1), 
		MEDIEVAL(2), 
		RENASSIANCE(3), 
		EARLY_INDUSTRIAL(4), 
		INDUSTRIAL(5), 
		POST_INDUSTRIAL(6),
		HI_TECH(7);
		
		/**
		 * Relative advancement to other tech levels
		 * Higher value means more advanced civilizations
		 */
		private final int value;
		
		/**
		 * TechLevel method
		 * This method sets the tech level
		 * @param v an int representing the enum type of tech level
		 */
		private TechLevel(int v) {
			value = v;
		}
		
		/**
		 * getValue method
		 * Returns the relative progression of Technology of the Planet to other Planets
		 * @return the value of progression
		 */
		public int getValue() {
			return value;
		}
		
		/**
		 * toString method
		 * @return the object as a String
		 */
		public String toString() {
			return super.toString().replace('_', ' ');
		}
	}
	
	/**
	 * SpecialResources Enumerated Type
	 * This enum lists the types of Special resources a planet can have
	 * @author Team Bamf (Team 30)
	 */
	public enum SpecialResources {
		/**
		 * No Special Resources
		 */
		NONE, 
		
		/**
		 * Rich in Minerals
		 * Decrease in price of Ores
		 */
		MINERAL_RICH, 
		
		/**
		 * Poor in Minerals
		 * Increase in the price of Ores
		 */
		MINERAL_POOR, 
		
		/**
		 * Poor in Water
		 * Increase in the price of Water
		 */
		DESERT, 
		
		/**
		 * Rich in Water
		 * Decrease in the price of Water
		 */
		LOTS_OF_WATER, 
		
		/**
		 * Rich in Food
		 * Decrease in the price of Food
		 */
		RICH_SOIL, 
		
		/**
		 * Poor in Food
		 * Increase in the price of Food
		 */
		POOR_SOIL, 
		
		/**
		 * Rich in Furs
		 * Decrease in the price of furs
		 */
		RICH_FAUNA, 
		
		/**
		 * Poor in Furs
		 * Increase in the price of Furs
		 */
		LIFELESS, 
		
		/**
		 * Rich in Narcotics
		 * Decrease in the price of Narcotics
		 */
		WEIRD_MUSHROOMS,
		
		/**
		 * Rich in Medicine
		 * Decrease in the price of Medicine
		 */
		LOTS_OF_HERBS,
		
		/**
		 * Rich in Games
		 * Decrease in the price of Games
		 */
		ARTISTIC,
		
		/**
		 * Rich in Firearms
		 * Decrease in price of Firearms
		 */
		WAR_LIKE;
		
		/**
		 * toString method
		 * @return the object as a String
		 */
		public String toString() {
			return super.toString().replace('_', ' ');
		}
	}

	/**
	 * Gets the Planet's name
	 * @return the name of the planet
	 */
	public String getName() {
		return name;
	}
	

	/**
	 * getInventory method
	 * Gets the inventory for subclasses to use
	 * @return the TradeEntity's inventory
	 */
    public Inventory getInventory(){
		return inventory;
	}
	
	/**
	 * setInventory method
	 * This method sets the inventory for the trade entity
	 * @param i the inventory
	 */
	private void setInventory(Inventory i) {
		inventory = i;
	}
	
	/**
	 * buy method
	 * This method allows Player to trade with said trade entity by buying cargo
	 * @param type which resource the player is buying
	 * @param amount how much of the resource the player is buying
	 * @param tradePartner the player trading with the TradeEntity
	 */
	public final void buy(TradeGood type, int amount, Player tradePartner) {
		/**
		 * totalCost is the cost of the total inventory
		 */
		final int totalCost = prices.get(type) * amount;
		tradePartner.pay(totalCost);
		inventory.remove(type, amount);
		tradePartner.addCargo(type, amount);
	}
	
	/**
	 * getInventoryAmount method
	 * This method collects the amount of available resources
	 * @param resource the resources that we are trying to count
	 * @return the amount of that resource that is available on the planet
	 */
	public int getInventoryAmount(TradeGood resource) {
		return inventory.getAmount(resource);
	}

	/**
	 * sell method
	 * This method allows Player to trade with said trade entity by selling cargo
	 * @param type which resource the player is selling
	 * @param amount how much of the resource the player is selling
	 * @param tradePartner the player trading with the TradeEntity
	 */
	public final void sell(TradeGood type, int amount, Player tradePartner) {
		/**
		 * totalCost is the total cost to sell all of the inventory
		 */
		final int totalCost = prices.get(type) * amount;
		tradePartner.recieve(totalCost);
		inventory.add(type, amount);
		tradePartner.removeCargo(type, amount);
	}
	
	/**
	 * getSellPrice method
	 * This method gets the selling price of a resource
	 * @param resource that will be sold
	 * @return the sell price of the resource
	 */
	public int getPrice(TradeGood resource) {
		return prices.get(resource);
	}
}
